home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------*
- | File: grep.c - First release MLO 920611 |
- | Last revised: v1.1 MLO 920612 |
- | Unix-like grep utility, for rev. 37 or greater |
- | (OS 2.04) of the Amiga DOS. See Syntax() for a |
- | short description of this program. |
- *------------------------------------------------*/
-
- /**
- | #include files
- **/
-
- #include <stdio.h> /* Standard library */
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <exec/types.h> /* AmigaDOS includes */
- #include <exec/memory.h>
- #include <dos/dos.h>
- #include <dos/dosasl.h>
- #include <dos/dosextens.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
-
- /**
- | #define's and local stuff
- **/
-
- #define REVISION "1.1" /* Program version */
- #define LAST_CHANGED "920612"
-
- typedef short int Boolean; /* Boolean variables */
-
- #define True 1
- #define False 0
-
- #define MATCH_STATUS 0 /* Exit status */
- #define NOMATCH_STATUS 5
- #define ERROR_STATUS 10
-
- #define OS2_REVISION 37 /* AmigaDOS min. release (2.04) */
-
- #define FILENAME_MAX 128 /* Max. length of file names */
- #define LINE_LENGTH 256 /* Max. length of an input line */
-
- /**
- | Version Tag string
- **/
-
- char VersionTag[] = "\0$VER: grep v" REVISION " - MLO " LAST_CHANGED;
-
- /**
- | Global variables: flags for various program options, exit status
- **/
-
- Boolean CountOnly = False;
- Boolean IgnoreCase = False;
- Boolean PrintAll = False;
- Boolean PrintName = False;
- Boolean LineNumber = False;
- Boolean Reverse = False;
- Boolean StarEnabled = False;
- Boolean BreakFlag = False;
- int Status = MATCH_STATUS;
-
- /**
- | Global varables: program buffers, pointers to AmigaDOS structures
- **/
-
- extern struct DosLibrary *DOSBase; /* Opened from c.o */
-
- char *Pattern = NULL;
- char *Line = NULL;
- struct AnchorPath *pAP = NULL;
- size_t APlength = sizeof(struct AnchorPath) + FILENAME_MAX;
-
- /**
- | ANSI procedure prototypes
- **/
-
- Boolean CheckBreak(void);
- void Cleanup(void);
- int CXBRK(void);
- void DoTheStuff(FILE *fp, char *name);
- void Error(void);
- void Init(void);
- char *NextFile(char *pattern);
- void NoMem(void);
- void Syntax(void);
-
- main(
- int argc,
- char **argv
- ){
-
- /**
- | Main program: general initialisation, then loop on program options.
- **/
-
- Init();
-
- while (--argc) {
- if ( ((*++argv)[0] == '-') ) {
- int i=1;
- char c;
-
- while (c = (*argv)[i++]) {
- switch (c) {
- case 'c':
- case 'C':
- CountOnly = True;
- break;
- case 'f':
- case 'F':
- PrintAll = True;
- break;
- case 'i':
- case 'I':
- IgnoreCase = True;
- break;
- case 'l':
- case 'L':
- PrintName = True;
- break;
- case 'n':
- case 'N':
- LineNumber = True;
- break;
- case 'v':
- case 'V':
- Reverse = True;
- break;
- default:
- Syntax();
- Error();
- }
- }
- } else if ((*argv)[0] == '?') {
- Syntax();
- Cleanup();
- } else {
- break;
- }
- }
-
- /**
- | First (required) argument: pattern to search for.
- | As the pattern can be everywhere in the input line,
- | put a '*' before and after before converting to the
- | internal system format.
- **/
-
- if (argc--) {
- size_t i = strlen(*argv);
- size_t j = i + 3;
- char *temp;
- char star[] = "*";
-
- if ((temp = malloc(j)) == NULL) NoMem();
- else {
- if ((Pattern = malloc(j *= 3)) == NULL) {
- free(temp);
- NoMem();
- }
- }
-
- *temp = *star;
- strcpy(temp+1, *argv);
- strcpy(temp+1+i, star);
-
- if (IgnoreCase) (void) ParsePatternNoCase(temp, Pattern, j);
- else (void) ParsePattern(temp, Pattern, j);
-
- free(temp);
- Status = NOMATCH_STATUS;
-
- } else {
- Syntax();
- Error();
- }
-
- /**
- | Following (optional) arguments: file patterns.
- | They will be decoded, and every file in turn scanned for the
- | given pattern; if no argument is given, scan stdin.
- | If a break (CTRL-C) is detected from DoTheStuff() (and then
- | BreakFlag is non-zero) we must re-enter NextFile to release
- | the pattern matching internal stuff (calling MatchEnd()).
- **/
-
- if (argc) {
- while (!BreakFlag && argc--) {
- char *fil_nam;
-
- ++argv;
- while ((fil_nam = NextFile(*argv)) != NULL) {
- FILE *fp;
-
- if ((fp = fopen(fil_nam, "r")) == NULL) {
- printf("Couldn't open file \"%s\" ...\n", fil_nam);
- Status = ERROR_STATUS;
- } else {
- DoTheStuff(fp, fil_nam);
- fclose(fp);
- }
- }
- }
- } else {
- DoTheStuff(stdin, NULL);
- }
-
- Cleanup();
- }
-
- Boolean CheckBreak(void)
- {
-
- /**
- | Internal CTRL-C detection routine (the signal is cleared
- | from the call). An internal attention flag i set up, and
- | non-zero is returned as function value.
- **/
-
- if (!BreakFlag &&
- ((SetSignal(0, SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C))
- BreakFlag = True;
-
- return BreakFlag;
- }
-
- void Cleanup(void)
- {
-
- /**
- | Releases all system resources, then terminates the program
- | returning 'Status' to the operating system.
- **/
-
- if (pAP != NULL) FreeMem(pAP, APlength);
- if (Line != NULL) free(Line);
- if (Pattern != NULL) free(Pattern);
- if (StarEnabled) DOSBase->dl_Root->rn_Flags &= ~RNF_WILDSTAR;
-
- exit(Status);
- }
-
- int CXBRK(void)
- {
-
- /**
- | Supersedes SAS-C internal CTRL-C handling routine,
- | that detects CTRL-C on I/O etc.
- | That one sets the internal attention flag, then waits
- | (until CheckBreak() will be called).
- **/
-
- BreakFlag = True;
- return 0;
- }
-
- void DoTheStuff(
- FILE *fp,
- char *name
- ){
-
- /**
- | Central control routine.
- | Scans the file looking for the given pattern, and producing the
- | required output.
- **/
-
- long lineCount = 0; /* Number of read lines */
- long how_many = 0; /* Number of matching lines */
- Boolean match; /* 'File name printed' flag */
- Boolean file_out = False;
-
- if (PrintAll) {
- file_out = True;
- printf("Scanning file \"%s\" ...\n", name);
- }
-
- while (!CheckBreak() && fgets(Line, LINE_LENGTH, fp) != NULL) {
- lineCount++;
- match = IgnoreCase ? MatchPatternNoCase(Pattern, Line) :
- MatchPattern(Pattern, Line);
-
- if (match) {
- if (Status == NOMATCH_STATUS) Status = MATCH_STATUS;
- if (!Reverse) {
-
- Gotcha:
- if (CountOnly) {
- how_many++;
- } else {
- if (PrintName && !file_out) {
- file_out = True;
- if (name != NULL) printf("In file \"%s\" ...\n", name);
- }
- if (LineNumber) printf("%ld: ", lineCount);
- fputs(Line, stdout);
- }
- }
- } else {
- if (Reverse) goto Gotcha;
- }
- }
-
- if (!BreakFlag && CountOnly && how_many) {
- if (PrintName && name != NULL) printf("In file \"%s\": ", name);
- printf("%ld matches.\n", how_many);
- }
-
- if (how_many = ferror(fp)) {
- printf("DOS error %ld while reading file \"%s\" ...\n",
- how_many, name);
- Status = ERROR_STATUS;
- }
- }
-
- void Error(void)
- {
- Status = ERROR_STATUS;
- Cleanup();
- }
-
- void Init(void)
- {
-
- /**
- | Initialisation routine.
- | Checks dos.library version number; enables (if not already enabled)
- | the use of the '*' as wildcard character; and obtains memory for
- | the buffers needed to work.
- **/
-
- if (DOSBase->dl_lib.lib_Version < OS2_REVISION) {
- printf("Unable to open \"dos.library\" rev. %d ...\n", OS2_REVISION);
- Error();
- }
-
- if (StarEnabled = !(DOSBase->dl_Root->rn_Flags & RNF_WILDSTAR)) {
- DOSBase->dl_Root->rn_Flags |= RNF_WILDSTAR;
- }
-
- if ((pAP = AllocMem(APlength, MEMF_CLEAR)) == NULL ||
- (Line = malloc(LINE_LENGTH)) == NULL) {
- NoMem();
- }
- pAP->ap_Strlen = FILENAME_MAX;
- pAP->ap_BreakBits = SIGBREAKF_CTRL_C;
- }
-
- char *NextFile(
- char *pattern
- ){
-
- /**
- | Calls MatchFirst()/MatchNext() for the next file in the pattern;
- | if a break has been detected NextFile() exits immediately (then
- | this program will be terminated); otherwise the routine checks
- | for errors, then exits.
- **/
-
- static Boolean first_entry = True;
- long error;
-
- if (BreakFlag) goto Clear;
-
- error = first_entry ? MatchFirst(pattern, pAP) : MatchNext(pAP);
-
- if (pAP->ap_FoundBreak) {
- BreakFlag = True;
- goto Clear;
- }
-
- if (error) {
- if (error == ERROR_NO_MORE_ENTRIES) {
- if (first_entry) {
- printf("\"%s\": no such file(s) ...\n", pattern);
- }
- } else {
- printf("DOS error %ld returned from MatchFirst/MatchNext ...\n",
- error);
- }
- first_entry = True;
-
- Clear:
- MatchEnd(pAP);
- return NULL;
- }
-
- first_entry = False;
- return pAP->ap_Buf;
- }
-
- void NoMem(void)
- {
- puts("Couldn't obtain heap memory ...\n");
- Error();
- }
-
- void Syntax(void)
- {
- printf("\n\t\t%s\n\n", VersionTag + 7);
- puts("\tSyntax: grep [options] pattern [ File [ File [ ... ]]\n");
- puts("Searches files (a pattern can be given in the file name(s)), for");
- puts("lines containing a given pattern (with the AmigaDOS conventions).");
- puts("If no file names are given, grep assumes standard input.");
- puts("Exit status is 0 if any matches are found, 5 (warning) if none,");
- puts("10 (error) for unreadable files or other errors.\n");
- puts("Options: -c Print only the number of the matching lines;");
- puts(" -f Print the name of all the scanned files;");
- puts(" -i Ignore upper/lower case distinctions in the comparison;");
- puts(" -l Print the name of the files with matching lines (once);");
- puts(" -n Precede each line by its line number in the file;");
- puts(" -v Print all lines but those that contain the pattern.\n");
- }
-